package zhishuang.wang.sansi.fcms.protocol;

/**
 * @Author Zhishuang.Wang
 * @Date 2023/7/5 10:53
 * @Email 1406110602@qq.com
 */


import zhishuang.wang.sansi.tools.check.CrcCheck;

import java.util.Arrays;

public class ProtocolPackage {
    public ProtocolPackage() {
    }

    public static byte[] baseX9Facakge(byte[] data, int dataLen, String deviceId, int folNum, int cmd, int flag) {
        if (data != null && data.length < dataLen) {
            return null;
        } else if (deviceId.length() != 16) {
            return null;
        } else {
            if (data == null) {
                dataLen = 0;
            }

            int baseLen = dataLen + 15;
            byte[] baseByte = new byte[baseLen];
            baseByte[0] = 2;
            byte[] devBytes = hexToBytes(deviceId);
            System.arraycopy(devBytes, 0, baseByte, 1, 8);
            byte[] folNumBytes = addIntToByte(folNum, 2);
            System.arraycopy(folNumBytes, 0, baseByte, 9, 2);
            baseByte[11] = (byte)(flag & 255);
            baseByte[12] = (byte)(cmd & 255);
            if (data != null) {
                System.arraycopy(data, 0, baseByte, 13, dataLen);
            }

            int crc16res = CrcCheck.sumCheckCal(baseByte, 1, baseLen - 2);
            baseByte[baseLen - 2] = (byte)(crc16res & 255);
            baseByte[baseLen - 1] = 3;
            return baseByte;
        }
    }

    public static byte[] baseFcmsPackage(byte[] data, int dataLen) {
        if (data.length < dataLen) {
            return null;
        } else {
            int baseLen = dataLen + 6;
            byte[] baseByte = new byte[baseLen];
            baseByte[0] = 2;
            baseByte[1] = 48;
            baseByte[2] = 48;
            System.arraycopy(data, 0, baseByte, 3, dataLen);
            int crc16res = CrcCheck.doCrcByTable(baseByte, 1, baseLen - 3);
            baseByte[baseLen - 3] = (byte)(crc16res >> 8 & 255);
            baseByte[baseLen - 2] = (byte)(crc16res & 255);
            baseByte[baseLen - 1] = 3;
            return baseByte;
        }
    }

    public static byte[] baseDataToSend(byte[] data) {
        if (data != null && data.length != 0) {
            int sendLen = data.length * 2;
            byte[] sendData = new byte[sendLen];

            int j = 0;
            sendData[j++] = 2;

            for(int i = 1; i < data.length - 1; ++i) {
                if (data[i] == 2) {
                    sendData[j++] = 27;
                    sendData[j++] = -25;
                } else if (data[i] == 3) {
                    sendData[j++] = 27;
                    sendData[j++] = -24;
                } else if (data[i] == 27) {
                    sendData[j++] = 27;
                    sendData[j++] = 0;
                } else {
                    sendData[j++] = data[i];
                }
            }

            sendData[j++] = 3;
            return Arrays.copyOf(sendData, j);
        } else {
            return null;
        }
    }

    public static byte[] revToBaseData(byte[] data) {
        if (data != null && data.length != 0) {
            int baseLen = data.length;
            byte[] baseData = new byte[baseLen];

            int j = 0;
            baseData[j++] = 2;

            for(int i = 1; i < data.length - 1; ++i) {
                if (data[i] == 27) {
                    if (data[i + 1] == -25) {
                        baseData[j++] = 2;
                    } else if (data[i + 1] == -24) {
                        baseData[j++] = 3;
                    } else if (data[i + 1] == 0) {
                        baseData[j++] = 27;
                    }

                    ++i;
                } else {
                    baseData[j++] = data[i];
                }
            }

            baseData[j++] = 3;
            return Arrays.copyOf(baseData, j);
        } else {
            return null;
        }
    }

    public static byte[] fcmsPackageToSend(byte[] data, int dataLen) {
        byte[] packeData = baseFcmsPackage(data, dataLen);
        return packeData != null ? baseDataToSend(packeData) : null;
    }

    public static byte[] x9FacakgeToSend(byte[] data, int dataLen, String deviceId, int folNum, int cmd, int flag) {
        byte[] packeData = baseX9Facakge(data, dataLen, deviceId, folNum, cmd, flag);
        return packeData != null ? baseDataToSend(packeData) : null;
    }

    public static int getIntVal(byte[] data, int start, int size) {
        int dataLen = data.length;
        int endP = start + size;
        if (endP <= dataLen && size >= 1 && size <= 4) {
            int res = 0;

            for(int i = start; i < endP; ++i) {
                dataLen = data[i] & 255;
                res = (res << 8) + dataLen;
            }

            return res;
        } else {
            return 0;
        }
    }

    public static long getLongVal(byte[] data, int start, int size) {
        int dataLen = data.length;
        int endP = start + size;
        if (endP <= dataLen && size >= 1 && size <= 8) {
            long res = 0L;

            for(int i = start; i < endP; ++i) {
                dataLen = data[i] & 255;
                res = (res << 8) + (long)dataLen;
            }

            return res;
        } else {
            return 0L;
        }
    }

    public static String getHexStr(byte[] data, int start, int size) {
        String resStr = "";
        int dataLen = data.length;
        int endP = start + size;
        if (endP <= dataLen) {
            for(int i = start; i < endP; ++i) {
                resStr = resStr + String.format("%02X", data[i]);
            }
        }

        return resStr;
    }

    public static String getAcsiiStr(byte[] data, int start, int size) {
        String resStr = "";
        if (size > 0) {
            int dataLen = data.length;
            int endP = start + size;
            if (endP <= dataLen) {
                byte[] acsiiByte = Arrays.copyOfRange(data, start, endP);
                resStr = new String(acsiiByte);
            }
        }

        return resStr;
    }

    public static byte[] addIntToByte(int intVal, int size) {
        if (size > 0 && size < 5) {
            byte[] data = new byte[size];

            for(int i = size - 1; i >= 0; --i) {
                data[i] = (byte)(intVal & 255);
                intVal >>= 8;
            }

            return data;
        } else {
            return null;
        }
    }

    public static byte[] addLongToByte(long longVal, int size) {
        if (size > 0 && size < 9) {
            byte[] data = new byte[size];

            for(int i = size - 1; i >= 0; --i) {
                data[i] = (byte)((int)(longVal & 255L));
                longVal >>= 8;
            }

            return data;
        } else {
            return null;
        }
    }

    public static int acsiiToInt(byte acsii) {
        int res;
        if (acsii >= 48 && acsii <= 57) {
            res = acsii - 48;
        } else if (acsii >= 65 && acsii <= 70) {
            res = acsii - 65 + 10;
        } else if (acsii >= 97 && acsii <= 102) {
            res = acsii - 97 + 10;
        } else {
            res = acsii & 255;
        }

        return res;
    }

    public static byte[] hexToBytes(String hex) {
        if (hex != null && hex.length() != 0) {
            int len = hex.length();
            if (len % 2 != 0) {
                return null;
            } else {
                hex = hex.toUpperCase();
                len /= 2;
                byte[] data = new byte[len];
                byte[] hexbyte = hex.getBytes();

                for(int i = 0; i < len; ++i) {
                    int res = acsiiToInt(hexbyte[2 * i]);
                    data[i] = (byte)((res & 255) << 4);
                    res = acsiiToInt(hexbyte[2 * i + 1]);
                    res &= 255;
                    data[i] = (byte)(data[i] + res);
                }

                return data;
            }
        } else {
            return null;
        }
    }

    public static byte[] timeStringToX9Byte(String timeStr) {
        byte[] dataBuff = new byte[9];
        if (timeStr == null && timeStr.length() <= 13) {
            for(int i = 0; i < 9; ++i) {
                dataBuff[i] = 0;
            }
        } else {
            String yearStr = timeStr.substring(0, 4);
            String monthStr = timeStr.substring(4, 6);
            String dayStr = timeStr.substring(6, 8);
            String hourStr = timeStr.substring(8, 10);
            String minStr = timeStr.substring(10, 12);
            String secStr = timeStr.substring(12, 14);
            int year = Integer.valueOf(yearStr);
            int month = Integer.valueOf(monthStr);
            int day = Integer.valueOf(dayStr);
            int hour = Integer.valueOf(hourStr);
            int min = Integer.valueOf(minStr);
            int sec = Integer.valueOf(secStr);
            byte[] yearByte = addIntToByte(year, 2);
            System.arraycopy(yearByte, 0, dataBuff, 0, 2);
            dataBuff[2] = (byte)(month & 255);
            dataBuff[3] = (byte)(day & 255);
            dataBuff[4] = (byte)(hour & 255);
            dataBuff[5] = (byte)(min & 255);
            dataBuff[6] = (byte)(sec & 255);
            dataBuff[7] = 0;
            dataBuff[8] = 0;
        }

        return dataBuff;
    }

    public static String timeX9ByteToString(byte[] data, int start, int size) {
        String timeStr = "";
        int year = getIntVal(data, start, 2);
        int month = data[start + 2] & 255;
        int day = data[start + 3] & 255;
        int hour = data[start + 4] & 255;
        int min = data[start + 5] & 255;
        int sec = data[start + 6] & 255;
        timeStr = String.format("%04d%02d%02d%02d%02d%02d", year, month, day, hour, min, sec);
        return timeStr;
    }

    public static int dimGradeToPer(int grade) {
        ++grade;
        int percentage = (int)((double)grade * 3.125);
        if (percentage > 100) {
            percentage = 100;
        }

        return percentage;
    }

    public static int dimPerToGrade(int percentage) {
        int grade = (int)((double)percentage / 3.125);
        --grade;
        if (grade < 0) {
            grade = 0;
        }

        return grade;
    }
}
